﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;

namespace YArchitech.Revit
{
	public class HYCurve
	{
		public HYCurve(Curve curve)
		{
			this.curve = curve;
			if (curve.IsBound)
			{
				this.startPoint = curve.GetEndPoint(0);
				this.endPoint = curve.GetEndPoint(1);
				return;
			}
			this.isBound = false;
		}

		public XYZ StartPoint
		{
			get
			{
				return this.startPoint;
			}
		}

		public XYZ EndPoint
		{
			get
			{
				return this.endPoint;
			}
		}

		public void MakeUnBound()
		{
			this.isBound = false;
			this.curve.MakeUnbound();
		}

		public bool IsBound
		{
			get
			{
				this.isBound = this.curve.IsBound;
				return this.isBound;
			}
		}

		public Curve Curve
		{
			get
			{
				return this.curve;
			}
		}

		public XYZ IntersectionPoint(Curve otherCurve)
		{
			XYZ result = new XYZ();
			result = null;
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			SetComparisonResult setComparisonResult = this.curve.Intersect(otherCurve, out intersectionResultArray);
			if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
			{
				result = intersectionResultArray.get_Item(0).XYZPoint;
			}
			return result;
		}

		public List<XYZ> IntersectionAllPoint(Curve otherCurve)
		{
			List<XYZ> list = new List<XYZ>();
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			SetComparisonResult setComparisonResult = this.curve.Intersect(otherCurve, out intersectionResultArray);
			if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
			{
				IntersectionResultArrayIterator intersectionResultArrayIterator = intersectionResultArray.ForwardIterator();
				while (intersectionResultArrayIterator.MoveNext())
				{
					object obj = intersectionResultArrayIterator.Current;
					XYZ xyzpoint = (obj as IntersectionResult).XYZPoint;
					if (xyzpoint != null)
					{
						list.Add(xyzpoint);
					}
				}
			}
			return list;
		}

		public List<XYZ> GetLayLineXYZList(XYZ globalPoint, int count, double radio, double offSet)
		{
			List<XYZ> list = new List<XYZ>();
			if (globalPoint == null || count < 1 || radio < -0.0001)
			{
				throw new Exception("布置参数有错误");
			}
			List<XYZ> list2 = this.curve.Tessellate().ToList<XYZ>();
			double num = (double)list2.Count;
			if (count == 1)
			{
				if (radio < 0.0001)
				{
					if (globalPoint.DistanceTo(list2[0]) < globalPoint.DistanceTo(list2[(int)num - 1]))
					{
						list.Add(list2[0]);
					}
					else
					{
						list.Add(list2[(int)num - 1]);
					}
				}
				else if (globalPoint.DistanceTo(list2[0]) < globalPoint.DistanceTo(list2[(int)num - 1]))
				{
					list.Add(list2[(int)((double)list2.Count * radio + 0.5)]);
				}
				else
				{
					list.Add(list2[(int)((double)list2.Count * (1.0 - radio) + 0.5)]);
				}
			}
			else
			{
				double num2 = num / ((double)count + radio);
				if (globalPoint.DistanceTo(list2[0]) < globalPoint.DistanceTo(list2[(int)num - 1]))
				{
					for (int i = 0; i < count; i++)
					{
						int num3 = (int)Math.Floor(num2 * ((double)i + radio));
						int num4 = (int)Math.Ceiling(num2 * ((double)i + radio));
						double num5 = num2 * ((double)i + radio) - (double)num3;
						XYZ xyz = list2[num3];
						XYZ xyz2 = list2[num4];
						XYZ xyz3 = xyz2 - xyz;
						XYZ xyz4 = xyz + xyz3.GetLength() * num5 * xyz3.Normalize();
						list.Add(new XYZ(xyz4.X, xyz4.Y, offSet));
					}
				}
				else
				{
					double num6 = (num - 1.0) / 2.0;
					for (int j = 0; j < count; j++)
					{
						int num3 = (int)Math.Floor(num2 * ((double)j + radio));
						int num4 = (int)Math.Ceiling(num2 * ((double)j + radio));
						double num5 = num2 * ((double)j + radio) - (double)num3;
						if ((double)num4 > num - 1.0)
						{
							num4 = (int)num - 1;
						}
						if ((double)num3 > num - 1.0)
						{
							num3 = (int)num - 1;
						}
						int num7 = (int)((num6 - (double)num3) * 2.0);
						int num8 = (int)((num6 - (double)num4) * 2.0);
						XYZ xyz = list2[num4 + num8];
						XYZ xyz2 = list2[num3 + num7];
						XYZ xyz5 = xyz - xyz2;
						XYZ xyz6 = xyz2 + xyz5.GetLength() * num5 * xyz5.Normalize();
						list.Add(new XYZ(xyz6.X, xyz6.Y, offSet));
					}
				}
			}
			return list;
		}

		public List<XYZ> GetLayLineXYZList(XYZ globalPoint, double distance, double sideDistance, double offSet)
		{
			List<XYZ> list = new List<XYZ>();
			if (globalPoint == null || distance < -0.0001 || sideDistance < -0.0001 || Math.Abs(distance) < 1E-05)
			{
				throw new Exception("布置参数有错误");
			}
			List<XYZ> list2 = this.curve.Tessellate().ToList<XYZ>();
			double length = this.curve.Length;
			int num = (int)Math.Ceiling((length - sideDistance) / distance);
			if (length > sideDistance)
			{
				if (globalPoint.DistanceTo(list2[0]) < globalPoint.DistanceTo(list2[list2.Count - 1]))
				{
					for (int i = 0; i < num; i++)
					{
						double num2 = sideDistance + distance * (double)i;
						double num3 = 0.0;
						for (int j = 0; j < list2.Count; j++)
						{
							if (j > 0)
							{
								num3 += list2[j - 1].DistanceTo(list2[j]);
							}
							if (num2 < num3 && j > 0)
							{
								XYZ xyz = list2[j - 1];
								XYZ xyz2 = list2[j];
								double num4 = xyz.DistanceTo(xyz2) - (num3 - num2);
								XYZ xyz3 = (xyz2 - xyz).Normalize();
								XYZ xyz4 = xyz + xyz3 * num4;
								list.Add(new XYZ(xyz4.X, xyz4.Y, offSet));
								break;
							}
						}
					}
				}
				else
				{
					for (int k = 0; k < num; k++)
					{
						double num2 = sideDistance + distance * (double)k;
						double num5 = 0.0;
						for (int l = list2.Count - 1; l >= 0; l--)
						{
							if (l < list2.Count - 1)
							{
								num5 += list2[l].DistanceTo(list2[l + 1]);
							}
							if (num2 < num5 && l < list2.Count - 1)
							{
								XYZ xyz = list2[l + 1];
								XYZ xyz2 = list2[l];
								double num6 = xyz2.DistanceTo(xyz) - (num5 - num2);
								XYZ xyz5 = (xyz2 - xyz).Normalize();
								XYZ xyz6 = xyz + xyz5 * num6;
								list.Add(new XYZ(xyz6.X, xyz6.Y, offSet));
								break;
							}
						}
					}
				}
				return list;
			}
			throw new Exception("选择的线段过短，无法满足设置的参数");
		}

		public List<XYZ> GetLayLineXYZList(XYZ globalPoint, double distance, double sideDistance, double offSet, Autodesk.Revit.DB.Document doc)
		{
			List<XYZ> list = new List<XYZ>();
			double num = doc.ActiveView.GenLevel.Elevation + offSet;
			if (globalPoint == null || distance < -0.0001 || sideDistance < -0.0001 || Math.Abs(distance) < 1E-05)
			{
				throw new Exception("布置参数有错误");
			}
			if (sideDistance >= distance)
			{
				throw new Exception("边距值必须小于间距值");
			}
			List<XYZ> list2 = this.curve.Tessellate().ToList<XYZ>();
			XYZ xyz;
			XYZ xyz2;
			if (globalPoint.DistanceTo(list2[0]) < globalPoint.DistanceTo(list2[list2.Count - 1]))
			{
				xyz = list2[0];
				xyz2 = list2[0];
			}
			else
			{
				xyz = list2[list2.Count - 1];
				xyz2 = list2[list2.Count - 1];
			}
			double num2 = sideDistance;
			int num3 = 0;
			for (;;)
			{
				if (num3 > 0)
				{
					num2 = distance;
				}
				List<XYZ> list3;
				if (num2 <= 0.16404199475065617 && num3 == 0)
				{
					list3 = new List<XYZ>();
					list3.Add(xyz);
				}
				else
				{
					Arc otherCurve = doc.CreatYJKArc(xyz, num2, 0.0, Math.PI*2, XYZ.BasisX, XYZ.BasisY);
					list3 = this.IntersectionAllPoint(otherCurve);
				}
				if (list3 == null)
				{
					break;
				}
				if (list3.Count < 1)
				{
					if (list.Count <= 1)
					{
						list = new List<XYZ>();
						XYZ xyz3 = list2[(list2.Count - list2.Count % 2) / 2];
						list.Add(new XYZ(xyz3.X, xyz3.Y, num));
					}
				}
				else if (list3.Count == 1)
				{
					if (list.Count > 1)
					{
						return list;
					}
					xyz = list3[0];
					list.Add(new XYZ(list3[0].X, list3[0].Y, num));
				}
				else
				{
					if (list3.Count != 2)
					{
						return list;
					}
					if (list.Count > 1)
					{
						xyz2 = list[list.Count - 2];
					}
					if (xyz2.DistanceTo(list3[0]) > xyz2.DistanceTo(list3[1]))
					{
						list.Add(new XYZ(list3[0].X, list3[0].Y, num));
						xyz = list3[0];
					}
					else
					{
						list.Add(new XYZ(list3[1].X, list3[1].Y, num));
						xyz = list3[1];
					}
				}
				num3++;
				if (num3 >= 1000)
				{
					return list;
				}
			}
			throw new Exception("布置参数有错误");
		}

		public XYZ GetProject(XYZ point, bool unBound = false)
		{
			if (unBound)
			{
				this.curve.MakeUnbound();
			}
			IntersectionResult intersectionResult = new IntersectionResult();
			intersectionResult = this.curve.Project(point);
			XYZ result = null;
			if (intersectionResult != null)
			{
				result = intersectionResult.XYZPoint;
			}
			return result;
		}

		public XYZ GetEndPointNearProject(XYZ point)
		{
			XYZ result = null;
			XYZ project = this.GetProject(point, false);
			if (this.isBound)
			{
				if (project.DistanceTo(this.startPoint) < project.DistanceTo(this.endPoint))
				{
					result = this.startPoint;
				}
				else
				{
					result = this.endPoint;
				}
			}
			return result;
		}

		public bool PointIsOnCurve(XYZ point)
		{
			bool result = true;
			XYZ project = this.GetProject(point, false);
			if (this.isBound)
			{
				result = (!project.IsAlmostEqualTo(this.startPoint) && !project.IsAlmostEqualTo(this.endPoint));
			}
			return result;
		}

		private Curve curve;

		private bool isBound = true;

		private XYZ startPoint = new XYZ(0.0, 0.0, 0.0);

		private XYZ endPoint = new XYZ(0.0, 0.0, 0.0);
	}
}
